#ifndef FILECONTENTBASE_H
#define FILECONTENTBASE_H

#include <wx/string.h>

class HexEditViewBase;


class FileContentBase {
  public:


    typedef unsigned long long OffsetT;


    struct ExtraUndoData {
      HexEditViewBase* m_View;        ///< \brief View which was active while performing the change
      OffsetT          m_PosBefore;   ///< \brief Position before the change
      int              m_PosBeforeF;  ///< \brief View-defined flags before the change (for example bit no before the change)
      OffsetT          m_PosAfter;    ///< \brief Position after the change
      int              m_PosAfterF;
      inline ExtraUndoData( HexEditViewBase* view, OffsetT posBefore, int posBeforeF, OffsetT posAfter, int posAfterF )
        : m_View( view )
        , m_PosBefore( posBefore )
        , m_PosBeforeF( posBeforeF )
        , m_PosAfter( posAfter )
        , m_PosAfterF( posAfterF ) {
      }

      inline ExtraUndoData() {}
    };


    FileContentBase();


    virtual ~FileContentBase();


    virtual bool ReadFile( const wxString& fileName ) = 0;


    virtual bool WriteFile( const wxString& fileName ) = 0;


    bool Modified();


    void SetModified( bool modified );


    virtual OffsetT GetSize() = 0;


    virtual OffsetT Read( void* buff, OffsetT position, OffsetT length ) = 0;


    OffsetT Write( const ExtraUndoData& extraUndoData, const void* buff, OffsetT position, OffsetT length );


    OffsetT Remove( const ExtraUndoData& extraUndoData, OffsetT position, OffsetT length );


    OffsetT Add( const ExtraUndoData& extraUndoData, OffsetT position, OffsetT length, void* data = 0 );


    bool CanUndo();


    bool CanRedo();


    const ExtraUndoData* Undo();


    const ExtraUndoData* Redo();


    inline unsigned char ReadByte( OffsetT position ) {
      unsigned char val = 0;
      return ( Read( &val, position, 1 ) == 1 ) ? val : 0;
    }


    inline bool WriteByte( const ExtraUndoData& extraUndoData, OffsetT position, unsigned char val ) {
      return Write( extraUndoData, &val, position, 1 ) == 1;
    }


    static FileContentBase* BuildInstance( const wxString& fileName );

  protected:


    class ModificationData {
      public:


        inline ModificationData() {}


        virtual ~ModificationData() {}


        virtual void Apply() = 0;


        virtual void Revert() = 0;


        virtual OffsetT Length() = 0;

      private:

        ModificationData*   m_Next;     ///< \brief Next element in modificatoin list
        ModificationData*   m_Prev;     ///< \brief Previous element in modification list
        ExtraUndoData       m_Data;
        friend class FileContentBase;   ///< \brief To allow operations on m_Next and m_Prev
    };


    virtual ModificationData* BuildChangeModification( OffsetT position, OffsetT length, const void* data = 0 ) = 0;


    virtual ModificationData* BuildAddModification( OffsetT position, OffsetT length, const void* data = 0 ) = 0;


    virtual ModificationData* BuildRemoveModification( OffsetT position, OffsetT length ) = 0;


    inline void UndoNotifySaved() { m_UndoSaved = m_UndoCurrent; }


    inline void UndoClear() { RemoveUndoFrom( m_UndoBuffer ); m_UndoCurrent = 0; m_UndoSaved = 0; }

  private:

    ModificationData*   m_UndoBuffer;       ///< \brief Undo buffer
    ModificationData*   m_UndoLast;         ///< \brief Last element in undo buffer
    ModificationData*   m_UndoCurrent;      ///< \brief Current undo position
    ModificationData*   m_UndoSaved;

    class InvalidModificationData: public ModificationData {
        void    Apply() { }
        void    Revert() { }
        OffsetT Length() { return 0; }
    };

    static InvalidModificationData m_UndoInvalid;


    void InsertAndApplyModification( ModificationData* mod );
    void RemoveUndoFrom( ModificationData* mod );
    void ApplyModification( ModificationData* mod );
    void RevertModification( ModificationData* mod );
};

#endif
